/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ocm.auth.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.ocm.core.tool.utils.*;
import com.wf.captcha.SpecCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import com.ocm.auth.granter.ITokenGranter;
import com.ocm.auth.granter.TokenGranterBuilder;
import com.ocm.auth.granter.TokenParameter;
import com.ocm.auth.utils.TokenUtil;
import com.ocm.common.cache.CacheNames;
import com.ocm.core.log.exception.ServiceException;
import com.ocm.core.secure.AuthInfo;
import com.ocm.core.tool.api.R;
import com.ocm.core.tool.support.Kv;
import com.ocm.user.dto.UserRegisterDTO;
import com.ocm.user.entity.User;
import com.ocm.user.entity.UserInfo;
import com.ocm.user.feign.IUserClient;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import static com.ocm.core.launch.constant.TokenConstant.USER_TENANT;

/**
 * 认证模块
 *
 * @author Chill
 */
@RestController
@AllArgsConstructor
@Api(value = "用户授权认证", tags = "授权接口")
public class AuthController {

	private final RedisUtil redisUtil;
	private final IUserClient userClient;

	@PostMapping("token")
	@ApiOperation(value = "获取认证token", notes = "传入租户ID:tenantId,账号:account,密码:password")
	public R<AuthInfo> token(@ApiParam(value = "授权类型", required = true) @RequestParam(defaultValue = "password", required = false) String grantType,
							 @ApiParam(value = "刷新令牌") @RequestParam(required = false) String refreshToken,
							 @ApiParam(value = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId,
							 @ApiParam(value = "账号") @RequestParam(required = false) String account,
							 @ApiParam(value = "密码") @RequestParam(required = false) String password) {

		String userType = Func.toStr(Objects.requireNonNull(WebUtil.getRequest()).getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
		TokenParameter tokenParameter = new TokenParameter();
		tokenParameter.getArgs().set("tenantId", tenantId)
			.set("account", account)
			.set("password", password)
			.set("grantType", grantType)
			.set("refreshToken", refreshToken)
			.set("userType", userType);

		ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
		UserInfo userInfo = granter.grant(tokenParameter);

		if (userInfo == null || userInfo.getUser() == null || userInfo.getUser().getId() == null) {
			return R.fail(TokenUtil.USER_NOT_FOUND);
		}

		return R.data(TokenUtil.createAuthInfo(userInfo));
	}

	/**
	 * 注册 默认租户为用户
	 */
	@PostMapping("/register")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "注册", notes = "传入User")
	public R userRegister(@Valid @RequestBody  UserRegisterDTO form) {

		String phone = form.getPhone();
		String code = Objects.requireNonNull(WebUtil.getRequest()).getHeader(TokenUtil.CAPTCHA_HEADER_CODE);

		// 获取验证码
		String redisCode = String.valueOf(redisUtil.get(CacheNames.P_CAPTCHA_KEY+ phone));
		// 判断验证码
		if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
			throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
		}
		//加密密码
		User user = BeanUtil.copy(form,User.class);
		user.setBirthday(new Date());
		user.setPassword(DigestUtil.encrypt(form.getPassword()));

		R result = userClient.saveUser(user);
		if (!result.isSuccess()) {
			throw new ServiceException(result.getMsg());
		}
		return token("password",null,USER_TENANT,form.getAccount(),form.getPassword());
	}

	@GetMapping("/phoneCaptcha")
	@ApiOperation(value = "获取验证码")
	public R<String> phoneCaptcha( @RequestParam String phone) {
		//todo 模拟获取短信验证 不要忘记设置发送间隔 即同一手机号 ?条/小时

		Pattern p = Pattern.compile("^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$");
		if(!p.matcher(phone).matches())
			return R.fail("手机号格式错误");

		String verCode = "111111";
		// 存入redis并设置过期时间为30分钟
		redisUtil.set(CacheNames.P_CAPTCHA_KEY + phone, verCode, 30L, TimeUnit.MINUTES);
		// 将key和base64返回给前端
		return R.data(phone);
	}



	@GetMapping("/captcha")
	@ApiOperation(value = "获取验证码")
	public R<Kv> captcha() {
		SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
		String verCode = specCaptcha.text().toLowerCase();
		String key = UUID.randomUUID().toString();
		// 存入redis并设置过期时间为30分钟
		redisUtil.set(CacheNames.CAPTCHA_KEY + key, verCode, 30L, TimeUnit.MINUTES);
		// 将key和base64返回给前端
		return R.data(Kv.init().set("key", key).set("image", specCaptcha.toBase64()));
	}

}
